﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MLSharp.Clustering
{
	/// <summary>
	/// Extension methods for <see cref="IClusterNode"/>.
	/// </summary>
	public static class ClusterNodeExtensions
	{
		/// <summary>
		/// Gets statistics for the specified cluster.
		/// </summary>
		/// <param name="node"></param>
		/// <remarks>This can be used to build a description for the cluster.</remarks>
		/// <returns></returns>
		public static AttributeStatistic[] GetAttributeStatistics(this IClusterNode node)
		{
			//Get a reference to the dataset since we need that to iterate over the attributes.
			IDataSet ds = node.Instances[0].DataSet;

			IList<AttributeStatistic> statistics = new List<AttributeStatistic>();

			//Loop through each attribute
			for (int i=0; i < ds.Attributes.Count; i++)
			{
				AttributeStats stats = new AttributeStats();

				DataAttribute attribute = ds.Attributes[i];

				if (attribute.IsNumeric())
				{
					stats.NumericStats = new Stats();
				}
				else
				{
					stats.NominalCounts = new int[attribute.PossibleValues.Length];
				}

				foreach (Instance instance in node.Instances)
				{
					//If the value is missing, continue
					if (instance.IsValueMissing(i))
					{
						continue;
					}

					if (attribute.IsNumeric())
					{
						stats.NumericStats.Add(instance.Values[i]);
					}
					else
					{
						stats.NominalCounts[(int)instance.Values[i]]++;
					}

					stats.TotalCount++;
				}


				//Aggregate the stats
				if (attribute.IsNumeric())
				{
					stats.NumericStats.CalculateDerived();
					statistics.Add(new AttributeStatistic(attribute.Name, stats.NumericStats.Min, stats.NumericStats.Mean, stats.NumericStats.Max, stats.NumericStats.StdDev));
				}
				else
				{
					//Add an entry for each non-zero probability
					for (int j=0; j < attribute.PossibleValues.Length; j++)
					{
						if (stats.NominalCounts[j] > 0)
						{
							statistics.Add(new AttributeStatistic(attribute.Name, attribute.PossibleValues[j],
							                                      stats.NominalCounts[j]/(double) stats.TotalCount));
						}
					}
				}
			}

			return statistics.ToArray();
		}
	}
}
